using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using NSTM.Core;
using jstm.tests;
using System.Diagnostics;
using SampleImages.Generated;
using System.Reflection;
using System.IO;
using java.lang;
using jstm.transports.clientserver.socket;

namespace SampleImages
{
	/// <summary>
	/// This sample is compatible with the Java & GWT Images samples. Use the button to add
	/// images, and the mouse to drag them in the window.
	/// </summary>
	public partial class Form1 : Form
	{
		readonly Share _share;
		int _index;

		int _left, _top;
		bool _dragging;
		int _lastUpdate;

		public Form1()
		{
			InitializeComponent();

			// Register the object model which defines ImageInfo

			NSTM.Core.Site.Local.registerObjectModel( new ImagesObjectModel() );

			// Logs

			NSTM.Core.Site.Local.Committed += delegate( object sender, TransactionEventArgs e )
			{
				Debug.WriteLine( "Committed " + e.Transaction );
			};

			jstm.misc.Log.add( new Logger( this ) );

			// Auto socket tries to start a local socket server, if it fails because a
			// server is already present, it connects to it using a socket client instead.

			AutoSocket connection = new AutoSocket( 4444 );

			// Get the Group instance representing the server and its clients, here it
			// means all instances of the sample.

			Group serverAndClientsSites = (Group) connection.getServerAndClients();

			// Open a share in this group if there is none yet

			if( serverAndClientsSites.OpenShares.Count == 0 )
			{
				Transaction transaction = NSTM.Core.Site.Local.StartTransaction();
				serverAndClientsSites.OpenShares.Add( new Share() );
				transaction.Commit();
			}

			foreach( Share first in serverAndClientsSites.OpenShares )
				_share = first;

			foreach( jstm.core.TransactedObject o in _share )
				if( o is ImageInfo )
					Add( (ImageInfo) o );

			_share.Added += new EventHandler<ItemEventArgs<jstm.core.TransactedObject>>( _share_Added );
		}

		class Logger : jstm.misc.Log
		{
			Form1 _form;

			public Logger( Form1 form )
			{
				_form = form;
			}

			public override void onWrite( string str )
			{
				_form.textBox1.AppendText( str + Environment.NewLine );
			}
		}

		private void buttonAdd_Click( object sender, EventArgs e )
		{
			// Add an image info to the share

			Transaction transaction = NSTM.Core.Site.Local.StartTransaction();
			ImageInfo info = new ImageInfo();

			info.Url = "image" + _index++ + ".jpg";
			info.Left = 200;
			info.Top = 200;

			if( _index > 3 )
				_index = 0;

			_share.Add( info );

			transaction.Commit();
		}

		private void _share_Added( object sender, ItemEventArgs<jstm.core.TransactedObject> e )
		{
			if( e.Item is ImageInfo )
			{
				BeginInvoke( (EmptyDelegate) delegate
				{
					Add( (ImageInfo) e.Item );
				} );
			}
		}

		public delegate void EmptyDelegate();

		private void Add( ImageInfo info )
		{
			// Get the image data that correspond to the the url

			Assembly a = typeof( jstm.examples.images.Images ).Assembly;
			java.io.InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream( info.Url );
			byte[] data = new byte[input.available()];
			input.read( data );

			// Draw it at given coordinates

			PictureBox image = new PictureBox();
			image.Image = Image.FromStream( new MemoryStream( data ) );
			image.Left = info.Left;
			image.Top = info.Top;
			image.SizeMode = PictureBoxSizeMode.AutoSize;
			Controls.Add( image );
			image.BringToFront();

			buttonAdd.BringToFront();

			// Listen to image info events and move image accordingly

			info.PropertyChanged += delegate( object sender, PropertyChangedEventArgs e )
			{
				if( e.PropertyName == "Left" )
				{
					BeginInvoke( (EmptyDelegate) delegate
					{
						image.Left = info.Left;
					} );
				}

				if( e.PropertyName == "Top" )
				{
					BeginInvoke( (EmptyDelegate) delegate
					{
						image.Top = info.Top;
					} );
				}
			};

			// Listen to image mouse events and update image info during drag

			image.MouseDown += delegate( object sender, MouseEventArgs e )
			{
				_left = e.X;
				_top = e.Y;
				_dragging = true;
			};

			image.MouseMove += delegate( object sender, MouseEventArgs e )
			{
				int now = Environment.TickCount;

				if( _dragging && now > _lastUpdate + 30 )
				{
					_lastUpdate = now;

					Transaction transaction = NSTM.Core.Site.Local.StartTransaction();

					info.Left += e.X - _left;
					info.Top += e.Y - _top;

					transaction.BeginCommit( null, null );
				}
			};

			image.MouseUp += delegate( object sender, MouseEventArgs e )
			{
				_dragging = false;
			};
		}
	}
}